using System;
using System.Collections.Generic;
using BSDS.Commands.Commands.Implementation;
using BSDS.Core.Infrastructure.Logging;
using BSDS.Core.Model.Services;
using BSDS.Core.Model.Services.Geocoding;
using BSDS.Core.Model.Services.Jobs;
using BSDS.Core.Model.Services.Uploading;
using BSDS.Core.Data.Local;

namespace BSDS.Commands.Commands.Creation.Implementation
{
    public class GeocodeCommandCreator : CommandCreatorBase
    {
        private readonly GeocodingService geoService;
        private readonly AccountService accountService;
        private readonly DataRepository dataRepository;
        private readonly JobRepository jobRepository;
        private readonly JobService jobService;
        private readonly UploadService uploadService;
        private readonly Logger logger;

        public GeocodeCommandCreator(GeocodingService geoService, AccountService accountService, DataRepository dataRepository, 
            JobRepository jobRepository, JobService jobService, UploadService uploadService, Logger logger)
        {
            this.geoService = geoService;
            this.accountService = accountService;
            this.dataRepository = dataRepository;
            this.jobRepository = jobRepository;
            this.jobService = jobService;
            this.uploadService = uploadService;
            this.logger = logger;
        }

        protected override bool Supports(Dictionary<string, string> parameters)
        {
            return parameters.Count >= 2 && parameters.ContainsKey("geocode") && parameters.ContainsKey("mode");
        }

        protected GeocodeCommandConfiguration CreateConfiguration(Dictionary<string, string> parameters)
        {
            var inputFilename = parameters["geocode"];
            var modeName = parameters["mode"];
            GeocodingMode geocodingMode;
            switch (modeName)
            {
                case "all":
                    geocodingMode = GeocodingMode.All;
                    break;
                case "empty":
                    geocodingMode = GeocodingMode.Empty;
                    break;
                case "reverse":
                    geocodingMode = GeocodingMode.Reverse;
                    break;
                default:
                    throw new ArgumentOutOfRangeException("Unsupported mode type: " + modeName);
            }

            var storeInOutputFile = false;
            var outputFilename = string.Empty;

            if (parameters.ContainsKey("outfile"))
            {
                storeInOutputFile = true;
                outputFilename = parameters["outfile"];
            }

            var portal = false;
            if (parameters.ContainsKey("portal"))
            {
                portal = true;
            }

            var resumeCompletedJob = false;
            var completedJobId = string.Empty;

            if (parameters.ContainsKey("resumeCompletedJob"))
            {
                resumeCompletedJob = true;
                completedJobId = parameters["resumeCompletedJob"];
            }

            var uploadAfterMerging = false;
            var dataSourceName = string.Empty;
            var entityTypeName = string.Empty;
            var queryKey = string.Empty;
            var outputFormat = DataFormat.OriginalFormat;
            var dropFilenamePrefix = string.Empty;

            if (parameters.ContainsKey("toPipe"))
            {
                outputFormat = DataFormat.Pipe;
            }
            
            if (parameters.ContainsKey("toTab"))
            {
                outputFormat = DataFormat.Tab;
            }

            if (parameters.ContainsKey("toXML"))
            {
                outputFormat = DataFormat.Xml;
            }

            if (parameters.ContainsKey("entity"))
            {
                entityTypeName = parameters["entity"];
            }

            if (parameters.ContainsKey("dropFilenamePrefix"))
            {
                dropFilenamePrefix = parameters["dropFilenamePrefix"];
            }

            if (parameters.ContainsKey("upload"))
            {
                uploadAfterMerging = true;

                if (!parameters.ContainsKey("name") || !parameters.ContainsKey("entity"))
                {
                    throw new ArgumentException("/name and /entity parameters must be specified if the /upload option is specified.");
                }
                dataSourceName = parameters["name"];

                if (parameters.ContainsKey("queryKey"))
                {
                    queryKey = parameters["queryKey"];
                }
            }

            return new GeocodeCommandConfiguration(inputFilename, geocodingMode, storeInOutputFile,
                 outputFilename, portal, outputFormat, uploadAfterMerging, dataSourceName, entityTypeName, queryKey, 
                 resumeCompletedJob, completedJobId, dropFilenamePrefix);
        }

        protected ICommand Create(GeocodeCommandConfiguration configuration)
        {
            return new GeocodeCommand(geoService, accountService, dataRepository, uploadService, jobRepository, 
                jobService, logger, configuration);
        }

        protected override ICommand Create(Dictionary<string, string> parameters)
        {
            var configuration = CreateConfiguration(parameters);

            return Create(configuration);
        }
    }
}